package cc.unitmesh.devins.idea.renderer.markdown

import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.sp
import cc.unitmesh.devins.idea.theme.IdeaAutoDevColors
import cc.unitmesh.markdown.MarkdownTextParser
import org.intellij.markdown.MarkdownElementTypes
import org.intellij.markdown.MarkdownTokenTypes
import org.intellij.markdown.ast.ASTNode
import org.intellij.markdown.ast.getTextInNode
import org.intellij.markdown.flavours.gfm.GFMElementTypes
import org.intellij.markdown.flavours.gfm.GFMTokenTypes

/**
 * Utility object for rendering inline Markdown formatting to AnnotatedString.
 * Handles bold, italic, strikethrough, code spans, links, and images.
 */
object MarkdownInlineRenderer {

    /**
     * Build annotated string with inline formatting support.
     * Recursively processes child nodes and applies appropriate styles.
     */
    fun AnnotatedString.Builder.appendMarkdownChildren(
        node: ASTNode,
        content: String,
        codeBackground: Color
    ) {
        node.children.forEach { child ->
            when (child.type) {
                MarkdownTokenTypes.TEXT -> {
                    append(child.getTextInNode(content).toString())
                }
                MarkdownTokenTypes.WHITE_SPACE -> append(" ")
                MarkdownTokenTypes.EOL -> append(" ")
                MarkdownTokenTypes.SINGLE_QUOTE -> append("'")
                MarkdownTokenTypes.DOUBLE_QUOTE -> append("\"")
                MarkdownTokenTypes.LPAREN -> append("(")
                MarkdownTokenTypes.RPAREN -> append(")")
                MarkdownTokenTypes.LBRACKET -> append("[")
                MarkdownTokenTypes.RBRACKET -> append("]")
                MarkdownTokenTypes.LT -> append("<")
                MarkdownTokenTypes.GT -> append(">")
                MarkdownTokenTypes.COLON -> append(":")
                MarkdownTokenTypes.EXCLAMATION_MARK -> append("!")
                MarkdownTokenTypes.HARD_LINE_BREAK -> append("\n")

                MarkdownElementTypes.EMPH -> {
                    withStyle(SpanStyle(fontStyle = FontStyle.Italic)) {
                        appendMarkdownChildren(child, content, codeBackground)
                    }
                }
                MarkdownElementTypes.STRONG -> {
                    withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
                        appendMarkdownChildren(child, content, codeBackground)
                    }
                }
                GFMElementTypes.STRIKETHROUGH -> {
                    withStyle(SpanStyle(textDecoration = TextDecoration.LineThrough)) {
                        appendMarkdownChildren(child, content, codeBackground)
                    }
                }
                MarkdownElementTypes.CODE_SPAN -> {
                    withStyle(SpanStyle(
                        fontFamily = FontFamily.Monospace,
                        background = codeBackground,
                        fontSize = 12.sp
                    )) {
                        val codeText = MarkdownTextParser.extractCodeSpanText(child, content)
                        append(" $codeText ")
                    }
                }
                MarkdownElementTypes.INLINE_LINK -> {
                    appendInlineLink(child, content)
                }
                MarkdownElementTypes.AUTOLINK -> {
                    appendAutoLink(child, content)
                }
                GFMTokenTypes.GFM_AUTOLINK -> {
                    val url = child.getTextInNode(content).toString()
                    pushStringAnnotation("URL", url)
                    withStyle(SpanStyle(
                        color = IdeaAutoDevColors.Blue.c400,
                        textDecoration = TextDecoration.Underline
                    )) {
                        append(url)
                    }
                    pop()
                }
                MarkdownElementTypes.SHORT_REFERENCE_LINK,
                MarkdownElementTypes.FULL_REFERENCE_LINK -> {
                    appendMarkdownChildren(child, content, codeBackground)
                }
                MarkdownElementTypes.IMAGE -> {
                    val altText = MarkdownTextParser.extractImageAltText(child, content)
                    withStyle(SpanStyle(fontStyle = FontStyle.Italic)) {
                        append("[$altText]")
                    }
                }
                else -> {
                    if (child.children.isNotEmpty()) {
                        appendMarkdownChildren(child, content, codeBackground)
                    }
                }
            }
        }
    }

    /**
     * Append an inline link with URL annotation.
     */
    fun AnnotatedString.Builder.appendInlineLink(node: ASTNode, content: String) {
        val text = MarkdownTextParser.extractLinkText(node, content)
        val url = MarkdownTextParser.extractLinkDestination(node, content)

        pushStringAnnotation("URL", url)
        withStyle(SpanStyle(
            color = IdeaAutoDevColors.Blue.c400,
            textDecoration = TextDecoration.Underline
        )) {
            append(text)
        }
        pop()
    }

    /**
     * Append an autolink with URL annotation.
     */
    fun AnnotatedString.Builder.appendAutoLink(node: ASTNode, content: String) {
        val url = MarkdownTextParser.extractAutoLinkUrl(node, content)
        pushStringAnnotation("URL", url)
        withStyle(SpanStyle(
            color = IdeaAutoDevColors.Blue.c400,
            textDecoration = TextDecoration.Underline
        )) {
            append(url)
        }
        pop()
    }
}

